#include "gtlStrings.h"

namespace GTL { namespace Strings { 

	namespace UTF8
	{
		/// Code shamelessly stolen from Allegro 5.1
		size_t Encode( int codepoint, char* s )
		{
			uint32_t uc = codepoint;

			if (uc <= 0x7f) {
				s[0] = (char)uc;
				return 1;
			}

			if (uc <= 0x7ff) {
				s[0] = char(0xC0 | ((uc >> 6) & 0x1F));
				s[1] = char(0x80 |  (uc       & 0x3F));
				return 2;
			}

			if (uc <= 0xffff) {
				s[0] = char(0xE0 | ((uc >> 12) & 0x0F));
				s[1] = char(0x80 | ((uc >>  6) & 0x3F));
				s[2] = char(0x80 |  (uc        & 0x3F));
				return 3;
			}

			if (uc <= 0x10ffff) {
				s[0] = char(0xF0 | ((uc >> 18) & 0x07));
				s[1] = char(0x80 | ((uc >> 12) & 0x3F));
				s[2] = char(0x80 | ((uc >>  6) & 0x3F));
				s[3] = char(0x80 |  (uc        & 0x3F));
				return 4;
			}

			return 0;
		}

		size_t ByteWidth( int codepoint )
		{
			uint32_t uc = codepoint;

			if (uc <= 0x7f)
				return 1;
			if (uc <= 0x7ff)
				return 2;
			if (uc <= 0xffff)
				return 3;
			if (uc <= 0x10ffff)
				return 4;
			return 0;
		}

		size_t GetLength( const char* buf )
		{
			return mbstowcs(NULL,buf,0);
		}

#define IS_SINGLE_BYTE(c)  (((unsigned)(c) & 0x80) == 0)
#define IS_LEAD_BYTE(c)    (((unsigned)(c) - 0xC0) < 0x3E)
#define IS_TRAIL_BYTE(c)   (((unsigned)(c) & 0xC0) == 0x80)

		int Prev( const char* _buf, const char** out )
		{
			const uint8_t* buf = (const uint8_t*)_buf;

			int pos = 0;

			while (buf[pos-1]) {
				uint8_t c = buf[--pos];
				if (IS_SINGLE_BYTE(c) || IS_LEAD_BYTE(c))
					break;
			}
			
			if (out)
				*out = (const char*)(buf+pos);
			
			return -pos;
		}

		int Next( const char* _buf, const char** out )
		{
			const uint8_t* buf = (const uint8_t*)_buf;

			int pos = 0;

			while (buf[++pos]) {
				uint8_t c = buf[pos];
				if (IS_SINGLE_BYTE(c) || IS_LEAD_BYTE(c))
					break;
			}

			if (out)
				*out = (const char*)(buf+pos);

			return pos;
		}

		size_t GetOffset( const char* buf, size_t index )
		{
			size_t of = 0;
			while (index --> 0) {
				size_t n = Next(buf, &buf);
				of += n;
				if (!n) break;
			}
			return of;
		}

		eastl::string WideCharToUTF8( const wchar_t* str )
		{
			eastl::string ret;
			while (str && *str)
			{
				char temp[5] = {0};
				Encode(*str++, temp);
				ret += temp;
			}
			return ret;
		}
	}

}}